package com.yyplatform.frontend.platform.account.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;

import com.yyplatform.frontend.platform.account.dto.LoginResultDTO;
import com.yyplatform.frontend.platform.account.dto.LoginWechatAppFormDTO;
import com.yyplatform.frontend.platform.account.entity.UserAuthEntity;
import com.yyplatform.frontend.platform.account.entity.UserEntity;
import com.yyplatform.frontend.platform.account.repository.UserAuthRepository;
import com.yyplatform.frontend.platform.account.repository.UserRepository;
import com.yyplatform.frontend.platform.account.service.WechatAppLoginService;
import com.yyplatform.frontend.infra.enums.UserLoginTypeEnum;
import com.yyplatform.frontend.infra.exception.ErrorCode;
import com.yyplatform.frontend.infra.exception.ServiceException;
import com.yyplatform.frontend.infra.web.jwt.JwtTokenService;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;

/**
 * Created on 2024-10-18
 */
@Service
@Slf4j
@AllArgsConstructor
public class WechatAppLoginServiceImpl implements WechatAppLoginService {

    private UserRepository userRepository;
    private UserAuthRepository userAuthRepository;
    private JwtTokenService jwtTokenService;
    private WxMaService wxMaService;


    @Override
    public LoginResultDTO loginCheck(LoginWechatAppFormDTO loginFormDTO) {
        WxMaJscode2SessionResult sessionResult = null;
        try {
            sessionResult = wxMaService.getUserService().getSessionInfo(loginFormDTO.getCode());
        } catch (WxErrorException e) {
            log.error("wechat miniapp login error", e);
        }
        if (null == sessionResult) {
            throw ServiceException.of(ErrorCode.WECHAT_MIN_APP_LOGIN_SERVER_ERROR);
        }

        WxMaUserInfo wxMaUserInfo = wxMaService.getUserService()
                .getUserInfo(sessionResult.getSessionKey(), loginFormDTO.getEncryptedData(), loginFormDTO.getIv());
        if (null == wxMaUserInfo) {
            throw ServiceException.of(ErrorCode.WECHAT_MIN_APP_LOGIN_SERVER_ERROR);
        }

        if (StringUtils.isEmpty(sessionResult.getOpenid())) {
            throw ServiceException.of(ErrorCode.WECHAT_MIN_APP_LOGIN_SERVER_ERROR);
        }


        UserAuthEntity userAuthEntity = userAuthRepository.findByLoginTypeAndIdentifier(
                UserLoginTypeEnum.WEI_XIN_MIN_APP.getValue(),
                sessionResult.getOpenid());

        if (userAuthEntity != null) {
            UserEntity userEntity = userRepository.getReferenceById(userAuthEntity.getUserId());
            return buildLoginResult(userEntity, userAuthEntity);
        }

        Pair<UserEntity, UserAuthEntity> pair = saveNewUser(sessionResult, wxMaUserInfo);

        return buildLoginResult(pair.getLeft(), pair.getRight());
    }


    private Pair<UserEntity, UserAuthEntity> saveNewUser(WxMaJscode2SessionResult sessionResult,
            WxMaUserInfo wxUserInfo) {

        String userName = "微信用户" + RandomStringUtils.randomNumeric(4);


        UserEntity userEntity = new UserEntity();
        userEntity.setCity(wxUserInfo.getCity());
        userEntity.setProvince(wxUserInfo.getProvince());
        userEntity.setCountry(wxUserInfo.getCountry());
        userEntity.setGender(NumberUtils.toInt(wxUserInfo.getGender(), 0));
        userEntity.setEmail("");
        userEntity.setPhone("");
        userEntity.setNickname(wxUserInfo.getNickName());
        userEntity.setUserName(userName);

        userEntity.setEnabled(true);
        userEntity.setFaceUrl(wxUserInfo.getAvatarUrl());
        userEntity.setLanguage(wxUserInfo.getLanguage());
        userEntity.setRemark("");


        userRepository.save(userEntity);


        UserAuthEntity userAuthEntity =
                getUserAuthEntity(sessionResult, userEntity);


        userAuthRepository.save(userAuthEntity);

        return Pair.of(userEntity, userAuthEntity);
    }

    private static UserAuthEntity getUserAuthEntity(WxMaJscode2SessionResult sessionResult, UserEntity userEntity) {
        Date now = new Date();
        UserAuthEntity userAuthEntity = new UserAuthEntity();
        userAuthEntity.setUserId(userEntity.getId());
        userAuthEntity.setLoginType(UserLoginTypeEnum.WEI_XIN_MIN_APP.getValue());
        userAuthEntity.setIdentifier(sessionResult.getOpenid());
        userAuthEntity.setOpenId(sessionResult.getOpenid());
        userAuthEntity.setUnionId(sessionResult.getUnionid());
        userAuthEntity.setLastLoginTime(now);
        userAuthEntity.setPwdResetTime(now);
        userAuthEntity.setSalt("");
        userAuthEntity.setPassword("");
        return userAuthEntity;
    }


    private LoginResultDTO buildLoginResult(UserEntity userEntity, UserAuthEntity userAuthEntity) {


        Map<String, Object> data = new HashMap<>();
        data.put("userId", userEntity.getId());
        data.put("loginType", userAuthEntity.getLoginType());
        data.put("identifier", userAuthEntity.getIdentifier());


        String jwtToken = jwtTokenService.encode(String.valueOf(userEntity.getId()), data);
        LoginResultDTO loginResultDTO = new LoginResultDTO();

        loginResultDTO.setJwtToken(jwtToken);
        loginResultDTO.setLoginType(UserLoginTypeEnum.WEI_XIN_MIN_APP.getValue());
        loginResultDTO.setIdentifier(userAuthEntity.getIdentifier());


        return loginResultDTO;
    }


}
